#!/usr/bin/python3
# -*- coding:utf-8 -*-
"""
@File: SeleniumPlatform.py
@Author: lijk34925
@Date: 2024/5/20 20:05企业日志查询
@desc: 请补充本模块功能说明
"""

import os
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from BladeFerm.Lib.Common import logger as mylog
from BladeFerm.utils.basic_opration import is_dir_exist


class SeleniumPlatform(object):
    def __init__(self, params, excel_path=None):
        self.is_close = params.get("isClose", False)
        self.timeout = params.get("timeout", 100)
        options = webdriver.ChromeOptions()
        if self.is_close:
            options.add_argument('--headless')
        is_dir_exist(excel_path)
        prefs = {'profile.default_content_settings.popups': 0, "download.default_directory": excel_path}
        options.add_experimental_option("prefs", prefs)
        options.add_argument('disable-infobars')
        options.add_experimental_option("excludeSwitches", ["ignore-certificate-errors"])
        # 设置驱动路径
        driver_path = params.get("driver_path", False)
        self.browser = webdriver.Chrome(executable_path=driver_path, options=options)

    def get_platform_session(self, params):
        '''
        登录获取cookie或者token
        :param params:
        :return:
        '''
        cookies = ''
        index = 0
        result_login = False
        while index < 3:
            result = self.__login_system(**params)
            if result:
                result_login = True
                break
            index += 1
            time.sleep(1)
            mylog.warning(f'Retry login ,index : {index}')
        if not result_login:
            self.close_browser()
            mylog.error(f'登录失败')
        return cookies

    # 登录系统
    def __login_system(self, **params):
        username = params['username']
        password = params['password']
        url = params['jira_url']
        try:
            mylog.info(f'open url: {url}')
            self.browser.get(url)
            self.browser.maximize_window()
            # 显性等待，直到用户名控件加载出来才进行下一步
            WebDriverWait(self.browser, 10, 0.5).until(
                EC.presence_of_element_located((By.ID, "username")))
            mylog.info(f'begin input username: {username}')
            self.browser.find_element_by_id("username").send_keys(username)
            self.browser.find_element_by_id("password").send_keys(password)
            time.sleep(0.5)
            self.browser.find_element_by_xpath('//*[@id="submit_psd"]/input').click()
            mylog.info(f'click login')
            res = WebDriverWait(self.browser, 5, 0.5).until_not(
                EC.visibility_of_element_located(('xpath', '//*[@id="submit_psd"]/input')))
            mylog.info(f'login result : {res}')
        except Exception as e:
            mylog.error(e)
            res = False
        mylog.info('登录结果：' + str(res))
        return res

    # 打开统计页面
    def open_report_page(self):
        self.__fund_element('xpath', '//li[@data-url="/metrics/index"]').click()
        time.sleep(1)
        self.__fund_element('xpath', '//span[contains(text(),"全部视图")]').click()
        mylog.info(f"打开统计页面")

    # 打开报表
    def open_report(self, table_name):
        table_search_element = self.__fund_element('xpath', '//input[@placeholder="输入报表名称"]')
        table_search_element.clear()
        table_search_element.send_keys(table_name)
        table_search_element.send_keys(Keys.ENTER)
        time.sleep(0.5)
        tree = self.__fund_element('xpath', f'//div[@class="node-wrapper is-report"]/span[@title="{table_name}"]')
        tree.click()
        WebDriverWait(self.browser, 5, 0.5).until(
            EC.presence_of_element_located(
                (By.XPATH, f'//div[contains(@class,"header-tab")]/span[@title="{table_name}"]')))
        mylog.info(f"打开报表：{table_name}")

    # 关闭报表
    def close_report(self, report_name):
        time.sleep(1)
        title_xpath = f'//div[contains(@class,"header-tab")]/span[@title="{report_name}"]'
        title_xpath_ele = self.browser.find_element_by_xpath(title_xpath)
        title_xpath_ele.click()
        title_xpath_ele.find_element_by_xpath('../i[1]').click()
        mylog.info(f"关闭{report_name}")

    # 效能下载报表
    def layout_download(self, query_params):
        reset_xpath = '//div[@class="el-form-item__content"]//button[@type="button"]/span[contains(text(),"重置")]'
        self.__fund_element('xpath', reset_xpath).click()
        for parameter in query_params['parameterList']:
            input_type = parameter['inputType']
            if input_type == "select_date":
                self.__layout_date_select(parameter)
            elif input_type == "select_single":
                self.__layout_select_single(parameter)
            elif input_type == "select_list":
                self.__layout_select_list(parameter)
            elif input_type == "select_tree":
                self.__layout_select_tree(parameter)
            else:
                mylog.error(f"{parameter['label']}的控件类型未知：{input_type}！")
            time.sleep(1)
        export_xpath = '//div[contains(@class,"el-tooltip")]/button/span[contains(text(),"导出")]/..'
        self.__fund_element('xpath', export_xpath).click()
        mylog.info(f'导出报表！')
        (WebDriverWait(self.browser, self.timeout, 1).until(EC.element_to_be_clickable(
            (By.XPATH, export_xpath))))
        mylog.info(f'下载完成！')

    # 效能下载报表
    def frame_download(self, query_params):
        try:
            self.browser.switch_to.frame(0)
            for parameter in query_params['parameterList']:
                input_type = parameter['inputType']
                if input_type == "select_date_range":
                    self.__frame_select_date_range(parameter)
                elif input_type == "select_list_multi":
                    self.__frame_select_list_multi(parameter)
                else:
                    mylog.error(f"{parameter['label']}的控件类型未知：{input_type}！")
            export_xpath = '//div[contains(@class,"el-tooltip")]/button/span[contains(text(),"导出")]/..'
            self.__fund_element('xpath', export_xpath).click()
            mylog.info(f'导出报表！')
            (WebDriverWait(self.browser, self.timeout, 1).until(EC.element_to_be_clickable(
                (By.XPATH, export_xpath))))
            mylog.info(f'下载完成！')
        finally:
            self.browser.switch_to.default_content()

    def __fund_element(self, by, value, timeout=10, father=None):
        """查找元素

        Args:
            by (str): 表达式类型
            value (str): 表达式
            timeout (int): 最大等待时间
        """
        if father is None:
            father_element = self.browser
        else:
            father_element = father
        target = None
        t = 0
        while t < timeout:
            elements = father_element.find_elements(by, value)
            if elements:
                for element in elements:
                    if element.is_displayed() and element.is_enabled():
                        target = element
                        break
            if target is None:
                time.sleep(0.5)
                t += 0.5
            else:
                break
        return target

    # 效能日期选择器
    def __layout_date_select(self, config):
        # 展开下拉框
        date_xpath_1 = f'//label[contains(text(), "{config["label"]}")]/following-sibling::div'
        self.__fund_element('xpath', date_xpath_1).click()
        # 等待下拉展开
        time.sleep(0.5)
        # 点击预设的日期
        date_xpath_2 = f'//div[@class="btn-list"]/button[contains(text(),"{config["preset"]}")]'
        self.__fund_element('xpath', date_xpath_2).click()
        mylog.info(f'{config["label"]} 选择：{config["preset"]}')

    # 效能下拉单选框
    def __layout_select_single(self, config):
        # 展开下拉框
        xpath_down = f'//label[contains(text(), "{config["label"]}")]/following-sibling::div//div[contains(@class,"el-input")]'
        self.__fund_element('xpath', xpath_down).click()
        # 等待下拉展开
        time.sleep(0.5)
        # 匹配并点击选中值
        xpath_target = ('//div[contains(@class,"el-select-dropdown") and not(contains(@style, "display: none"))]//'
                        f'div/ul/li[@title="{config["equals"]}"]')
        self.__fund_element('xpath', xpath_target).click()
        mylog.info(f'{config["label"]} 选择：{config["equals"]}')

    # 效能下拉多选框
    def __layout_select_list(self, config):
        # 展开下拉框
        xpath_down = f'//label[contains(text(), "{config["label"]}")]/following-sibling::div//div[contains(@class,"el-input")]'
        self.__fund_element('xpath', xpath_down).click()
        # 等待下拉展开
        time.sleep(0.5)
        # 点击清除按钮
        xpath_clear = ('//div[contains(@class,"el-select-dropdown") and not(contains(@style, "display: none"))]//'
                       'div/button/span[contains(text(),"清除")]/..')
        self.__fund_element('xpath', xpath_clear).click()
        if 'all' in config and config['all'] is True:
            mylog.info(f'{config["label"]} 全选')
        else:
            # 如果不为全选，则过滤值
            # 在筛选框中输入过滤条件
            xpath_input = ('//div[contains(@class,"el-select-dropdown") and not(contains(@style, "display: none"))]//'
                           'div[@class="el-select-filterable"]//input')
            self.__fund_element('xpath', xpath_input).send_keys(config['equals'])
            time.sleep(0.3)
            mylog.info(f'{config["label"]} 选择：{config["equals"]}')
        # 点击全选按钮
        xpath_all = ('//div[contains(@class,"el-select-dropdown") and not(contains(@style, "display: none"))]//'
                     'div/button/span[contains(text(),"全选")]/..')
        self.__fund_element('xpath', xpath_all).click()  # 点击 全选
        # 点击确定按钮，提交
        xpath_ok = (
            '//div[contains(@class,"el-select-dropdown") and not(contains(@style, "display: none"))]//'
            'div/button/span[contains(text(),"确定")]/..')
        self.__fund_element('xpath', xpath_ok).click()

    # 效能下拉多选树
    def __layout_select_tree(self, config):
        # 展开下拉框
        xpath_down = f'//label[contains(text(), "{config["label"]}")]/following-sibling::div//div[contains(@class,"select-input")]'
        self.__fund_element('xpath', xpath_down).click()
        # 等待下拉展开
        time.sleep(0.5)
        # 点击清除按钮
        xpath_clear = ('//div[contains(@class,"tree-popper") and not(contains(@style, "display: none"))]//'
                       'div/button/span[contains(text(),"清除")]')
        self.__fund_element('xpath', xpath_clear).click()
        if 'all' in config and config['all'] is True:
            # 点击全选按钮
            xpath_all = ('//div[contains(@class,"tree-popper") and not(contains(@style, "display: none"))]//'
                         'div/button/span[contains(text(),"全选")]')
            self.__fund_element('xpath', xpath_all).click()
            mylog.info(f'{config["label"]} 全选')
        else:
            # 在筛选框中输入过滤条件，输入后，树自动展开到匹配的节点，渲染DOM
            xpath_input = ('//div[contains(@class,"tree-popper") and not(contains(@style, "display: none"))]//'
                           'div[@class="search-wapper"]//input')
            self.__fund_element('xpath', xpath_input).send_keys(config["equals"])
            # 点击并选中节点
            xpath_input = ('//div[contains(@class,"tree-popper") and not(contains(@style, "display: none"))]//'
                           f'div[@role="tree"]//span[@title="{config["equals"]}"]/../preceding-sibling::label')
            self.__fund_element('xpath', xpath_input).click()
            mylog.info(f'{config["label"]} 选择：{config["equals"]}')
        # 点击确定按钮，提交
        xpath_ok = ('//div[contains(@class,"tree-popper") and not(contains(@style, "display: none"))]//'
                    'div/button/span[contains(text(),"确定")]')
        self.__fund_element('xpath', xpath_ok).click()  # 点击 确定

    # 日期设置
    def __set_date(self, date, father):
        year, month, day = date.split('-')
        input_element = self.__fund_element(By.CSS_SELECTOR, 'div.bi-date-trigger', father=father)
        input_element.click()
        date_range_selector = self.__fund_element(By.CSS_SELECTOR, 'div.bi-dynamic-date-popup', father=father)
        # 点击年份下拉并选择
        self.__fund_element(By.CSS_SELECTOR, 'div.bi-year-combo', father=date_range_selector).click()
        year_selector = f'.//div[contains(@class, "bi-year-calendar")]//div[contains(text(),"{year}")]/..'
        self.__fund_element(By.XPATH, year_selector, father=date_range_selector).click()
        # 点击月份下拉并选择
        self.__fund_element(By.CSS_SELECTOR, 'div.bi-month-combo', father=date_range_selector).click()
        month_selector = f'.//div[contains(@class, "bi-month-popup")]//div[contains(text(),"{int(month)}")]/..'
        self.__fund_element(By.XPATH, month_selector, father=date_range_selector).click()
        # 点击日期下拉并选择
        day_selector = (f'.//div[@class="bi-card-layout"]//div[contains(@class,"bi-calendar-date-item") and '
                        f'not(contains(@class,"bi-tips"))]//div[contains(text(),"{int(day)}")]/..')
        self.__fund_element(By.XPATH, day_selector, father=date_range_selector).click()

    # 效能 日期选择，日期范围设置
    def __frame_select_date_range(self, config):
        label = config['label']
        values = config['range']
        start_date, end_date = values[0], values[1]
        frame_element_xpath = (f'//div[@class="fm-document-content"]//p[contains(text(),"{label}")]/'
                               f'ancestor::div[contains(@class,"bi-layout-responsive-flex")]')
        frame_element = self.__fund_element(By.XPATH, frame_element_xpath)
        start_element = self.__fund_element(By.XPATH, './div[2]/div/div[1]', father=frame_element)
        self.__set_date(start_date, start_element)
        end_element = self.__fund_element(By.XPATH, './div[2]/div/div[3]', father=frame_element)
        self.__set_date(end_date, end_element)

    # 效能 日期选择，日期范围设置
    def __frame_select_list_multi(self, config):
        label = config['label']
        values = config['range']
        frame_element_xpath = (f'//div[@class="fm-document-content"]//p[contains(text(),"{label}")]/'
                               f'ancestor::div[contains(@class,"bi-layout-responsive-flex")]')
        frame_element = self.__fund_element('xpath', frame_element_xpath)
        tg_panel = self.__fund_element('xpath', './/div[contains(@class,"bi-multi-select-trigger")]', 10, frame_element)
        for unit in values:
            exp_xpath = './/div[contains(@class,"bi-multi-select-editor")]'
            expand_element = self.__fund_element('xpath', exp_xpath, father=tg_panel)
            expand_element.click()
            input_path = './/div[contains(@class, "bi-editor")]/div/input'
            input_element = self.__fund_element('xpath', input_path, father=tg_panel)
            input_element.send_keys(unit)
            input_element.send_keys(Keys.ENTER)
            target_path = f'.//div[contains(@class,"bi-multi-tree-search-pane")]/ul/li/a[@title="{unit}"]'
            WebDriverWait(self.browser, self.timeout, 1).until(EC.element_to_be_clickable((By.XPATH, target_path)))
            target_element = self.__fund_element('xpath', target_path, father=tg_panel)
            target_element.click()
            mylog.info(f'select ele : {unit}')
        bi_panel = self.__fund_element('xpath', './/div[contains(@class,"bi-multi-tree-popup")]', 10, frame_element)
        btn_xpath = './/div[contains(@class,"bi-button-group")]/div[2]/div'
        btn_element = self.__fund_element('xpath', btn_xpath, father=bi_panel)
        btn_element.click()
        mylog.info(f'点击确定，{label} 选择完成！')

    # 关闭浏览器
    def close_browser(self):
        if self.is_close:
            self.browser.close()
            self.browser.quit()
        mylog.info(f"关闭浏览器和驱动，结果：{self.is_close}")
